package com.rshang.rsdp.service.impl;

import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.code.kaptcha.Producer;
import com.rshang.rsdp.annotation.Log;
import com.rshang.rsdp.bean.DataGrid;
import com.rshang.rsdp.bean.Response;
import com.rshang.rsdp.bean.TreeMenu;
import com.rshang.rsdp.common.Consts;
import com.rshang.rsdp.common.status.StatusCode;
import com.rshang.rsdp.common.status.UserStatusCode;
import com.rshang.rsdp.entity.TbUser;
import com.rshang.rsdp.entity.TbUserrole;
import com.rshang.rsdp.exception.RsdpSystemException;
import com.rshang.rsdp.kit.StrKits;
import com.rshang.rsdp.mapper.TbUserMapper;
import com.rshang.rsdp.mapper.TbUserroleMapper;
import com.rshang.rsdp.service.ITbUserService;
import com.rshang.rsdp.util.i18n.I18nMessage;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.UnauthorizedException;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.image.BufferedImage;
import java.util.*;

/**
 * <p>
 * 用户信息表 服务实现类
 * </p>
 *
 * @author zhangjun
 * @since 2017-07-21
 */
@Service
public class TbUserServiceImpl extends ServiceImpl<TbUserMapper, TbUser> implements ITbUserService {

    private static final Logger logger = LoggerFactory.getLogger(TbUserServiceImpl.class);

    @Autowired
    I18nMessage i18n;

    @Autowired
    Producer captchaProducer;

    @Autowired
    ObjectMapper jsonMapper;

    @Autowired
    TbUserroleMapper userRoleMapper;

    @Value("${shiro.hashIterations}")
    int hashIterations;

    @Value("${user.initPwd}")
    String defaultPwd;


    @Override
    @Cacheable(value = Consts.CACHE_USERROLE, key = "#userid", unless = "#result == null")
    public List<String> getRolesByUserId(String userid) {
        return baseMapper.getRolesByUserId(userid);
    }

    @Override
    @Cacheable(value = Consts.CACHE_USERAUTH, key = "#userid", unless = "#result == null")
    public List<String> getAuthsByUserId(String userid) {
        return baseMapper.getAuthsByUserId(userid);
    }

    @Override
    @Log(module = "系统登录", desc = "用户登陆验证")
    public Response userLogin(HttpServletRequest request) {
        HttpSession session = request.getSession();
        String vcode = StrKits.emptyToStr(request.getParameter("vcode"));
        String username = StrKits.emptyToStr(request.getParameter("username"));
        String userpass = StrKits.emptyToStr(request.getParameter("password"));

        //验证码错误
        if ("".equals(vcode) || !vcode.equals(session.getAttribute(Consts.KAPTCHA_SESSION_KEY))) {
            throw new RsdpSystemException(StatusCode.CAPTCHA_ERROR.getCode(), i18n.getMessage(StatusCode.CAPTCHA_ERROR.getKey()));
        }
        UsernamePasswordToken token = new UsernamePasswordToken(username, userpass);
        Subject currentUser = SecurityUtils.getSubject();
        try {
            currentUser.login(token);
        } catch (IncorrectCredentialsException e) {
            logger.error("登录失败{}", e.getMessage());//用户名或密码错误
            throw new RsdpSystemException(StatusCode.LOGIN_FAILED.getCode(), i18n.getMessage(StatusCode.LOGIN_FAILED.getKey()));
        } catch (ExcessiveAttemptsException e) {
            logger.error("登录失败{}", e.getMessage());//登录失败次数过多
        } catch (LockedAccountException e) {
            logger.error("登录失败{}", e.getMessage());//帐号已被锁定
        } catch (DisabledAccountException e) {
            logger.error("登录失败{}", e.getMessage());//帐号已被禁用
        } catch (ExpiredCredentialsException e) {
            logger.error("登录失败{}", e.getMessage());//帐号已过期
            //throw new ApplicationException(SystemError.LOGIN_FAILED.getCode(), SystemError.LOGIN_FAILED.getMessage());
        } catch (UnknownAccountException e) {
            logger.error("登录失败{}", e.getMessage());//帐号不存在
            throw new RsdpSystemException(UserStatusCode.USER_NOTFOUND.getCode(), i18n.getMessage(UserStatusCode.USER_NOTFOUND.getKey()));
        } catch (UnauthorizedException e) {
            logger.error("登录失败{}", e.getMessage());//您没有得到相应的授权
        } catch (Exception e) {
            logger.error("登录失败{}", e.getMessage());
        }
        return new Response("main");
    }

    @Override
    public void createKaptcha(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpSession session = request.getSession();

        response.setDateHeader("Expires", 0);

        // Set standard HTTP/1.1 no-cache headers.  
        response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");

        // Set IE extended HTTP/1.1 no-cache headers (use addHeader).  
        response.addHeader("Cache-Control", "post-check=0, pre-check=0");

        // Set standard HTTP/1.0 no-cache header.  
        response.setHeader("Pragma", "no-cache");

        // return a jpeg  
        response.setContentType("image/jpeg");

        // create the text for the image  
        String capText = captchaProducer.createText();

        if (logger.isDebugEnabled()) {
            logger.debug("******************验证码是: {}******************", capText);
        }

        // store the text in the session  
        session.setAttribute(Consts.KAPTCHA_SESSION_KEY, capText);

        // create the image with the text  
        BufferedImage bi = captchaProducer.createImage(capText);
        ServletOutputStream out = response.getOutputStream();

        // write the data out  
        ImageIO.write(bi, "jpg", out);
        try {
            out.flush();
        } finally {
            out.close();
        }
    }

    @Override
    @Cacheable(value = Consts.CACHE_MENUTREE, key = "#userid", unless = "#result=='[]'")
    public String getJsonMenuByUserId(String userid) throws JsonProcessingException {
        List<TreeMenu> result = new ArrayList<TreeMenu>();
        List<HashMap> menus = this.baseMapper.getMenuByUserId(userid);
        String type = "";
        if (menus.size() > 0) {
            result.add(new TreeMenu(0, 0, "根节点", true, "#"));
            for (HashMap map : menus) {
                type = StrKits.emptyToStr(map.get("AUTH_TYPE"));
                if ("A".equals(type))//权限
                {
                    result.add(new TreeMenu(Integer.parseInt(StrKits.emptyToStr(map.get("AUTH_ID"))),
                            Integer.parseInt(StrKits.emptyToStr(map.get("AUTH_PID"))),
                            StrKits.emptyToStr(map.get("AUTH_NAME")),
                            false,
                            StrKits.emptyToStr(map.get("AUTH_URL"))));
                } else //模块
                {
                    result.add(new TreeMenu(Integer.parseInt(StrKits.emptyToStr(map.get("AUTH_ID"))),
                            Integer.parseInt(StrKits.emptyToStr(map.get("AUTH_PID"))),
                            StrKits.emptyToStr(map.get("AUTH_NAME")),
                            true,
                            "#"));
                }
            }
        }
        return jsonMapper.writeValueAsString(result);
    }

    @Override
    @Cacheable(value = Consts.CACHE_USERMODULE, key = "#userid", unless = "#result.size()==0")
    public List<String> getModulesByUserId(String userid) {
        List<String> result = new ArrayList<String>();
        List<HashMap> menus = this.baseMapper.getMenuByUserId(userid);
        String type = "";
        if (menus.size() > 0) {
            for (HashMap map : menus) {
                type = StrKits.emptyToStr(map.get("AUTH_TYPE"));
                if ("M".equals(type))//权限
                {
                    result.add(StrKits.emptyToStr(map.get("AUTH_NAME")));
                }
            }
        }
        return result;
    }

    @Override
    public DataGrid getUserPageList(Page<HashMap> page, HttpServletRequest request) {
        String xm = StrKits.emptyToStr(request.getParameter("userxm"));
        String gh = StrKits.emptyToStr(request.getParameter("usergh"));
        page.setRecords(this.baseMapper.getUserPageList(page, xm, gh));
        return new DataGrid(page.getRecords(), page.getTotal());
    }

    @Override
    @Log(module = "用户管理", desc = "新增用户")
    @Transactional
    public Response addSave(HttpServletRequest request, String czr) {
        String userName = StrKits.emptyToStr(request.getParameter("username"));
        String userPass = StrKits.emptyToStr(request.getParameter("userpass"));
        String xm = StrKits.emptyToStr(request.getParameter("xm"));
        String phone = StrKits.emptyToStr(request.getParameter("phone"));
        String email = StrKits.emptyToStr(request.getParameter("email"));
        String gh = StrKits.emptyToStr(request.getParameter("gh"));
        String role = StrKits.emptyToStr(request.getParameter("sel_role"));

        TbUser user = new TbUser();
        user.setUserId(StrKits.uuid());
        user.setYxBz("1");
        user.setUserPass(new Md5Hash(userPass, null, hashIterations).toString());
        user.setLrr(czr);
        user.setXgr(czr);
        user.setUserName(userName);
        user.setUserXm(xm);
        user.setUserPhone(phone);
        user.setUserEmail(email);
        user.setUserGh(gh);

        if (baseMapper.insert(user) > 0)//新增
        {
            TbUserrole userRole = new TbUserrole();
            userRole.setRoleId(role);
            userRole.setUserId(user.getUserId());
            if (userRoleMapper.insert(userRole) <= 0) {
                return new Response(StatusCode.OPER_FAILED.getCode(), i18n.getMessage(StatusCode.OPER_FAILED.getKey()));
            }
        } else {
            return new Response(StatusCode.OPER_FAILED.getCode(), i18n.getMessage(StatusCode.OPER_FAILED.getKey()));
        }
        return new Response(StatusCode.SUCCESS.getCode(), i18n.getMessage(StatusCode.SUCCESS.getKey()));
    }

    @Override
    @Log(module = "用户管理", desc = "用户编辑")
    @Transactional
    public Response editSave(HttpServletRequest request, String czr) {
        String userid = StrKits.emptyToStr(request.getParameter("hid_id"));
        String xm = StrKits.emptyToStr(request.getParameter("xm"));
        String phone = StrKits.emptyToStr(request.getParameter("phone"));
        String email = StrKits.emptyToStr(request.getParameter("email"));
        String gh = StrKits.emptyToStr(request.getParameter("gh"));
        String role = StrKits.emptyToStr(request.getParameter("sel_role"));
        TbUser user = new TbUser();

        user.setUserId(userid);
        user.setXgr(czr);
        user.setXgsj(new Date());
        user.setUserXm(xm);
        user.setUserPhone(phone);
        user.setUserEmail(email);
        user.setUserGh(gh);

        if (baseMapper.updateById(user) > 0) {
            Map paramMap = new HashMap();
            paramMap.put("USER_ID", user.getUserId());
            userRoleMapper.deleteByMap(paramMap);
            TbUserrole userRole = new TbUserrole();
            userRole.setRoleId(role);
            userRole.setUserId(user.getUserId());
            if (userRoleMapper.insert(userRole) <= 0) {
                return new Response(StatusCode.OPER_FAILED.getCode(), i18n.getMessage(StatusCode.OPER_FAILED.getKey()));
            }
        } else {
            return new Response(StatusCode.OPER_FAILED.getCode(), i18n.getMessage(StatusCode.OPER_FAILED.getKey()));
        }
        return new Response(StatusCode.SUCCESS.getCode(), i18n.getMessage(StatusCode.SUCCESS.getKey()));
    }

    @Override
    public Response checkUserName(HttpServletRequest request) {
        TbUser user = new TbUser();
        user.setUserName(StrKits.emptyToStr(request.getParameter("username")));
        user.setYxBz("1");
        TbUser result = this.baseMapper.selectOne(user);

        if (result != null) {
            throw new RsdpSystemException(UserStatusCode.USERNAME_FOUND.getCode(), i18n.getMessage(UserStatusCode.USERNAME_FOUND.getKey()));
        }
        return new Response(StatusCode.SUCCESS.getCode(), i18n.getMessage(StatusCode.SUCCESS.getKey()));
    }

    @Override
    @Log(module = "用户管理", desc = "删除用户")
    @Transactional
    public Response deleteUser(HttpServletRequest request, String czr) {
        TbUser result = this.baseMapper.selectById(StrKits.emptyToStr(request.getParameter("id")));
        if ("admin".equals(result.getUserName()))//系统管理员不能删除
        {
            return new Response(UserStatusCode.ADMIN_NOTDEL.getCode(), i18n.getMessage(UserStatusCode.ADMIN_NOTDEL.getKey()));
        } else if ("0".equals(result.getYxBz()))//已删除
        {
            return new Response(UserStatusCode.USER_DELETED.getCode(), i18n.getMessage(UserStatusCode.USER_DELETED.getKey()));
        } else if ("1".equals(result.getYxBz()))//有效允许逻辑删除
        {
            result.setXgr(czr);
            result.setXgsj(new Date());
            result.setYxBz("0");
            if (this.baseMapper.updateById(result) > 0) {
                return new Response(StatusCode.SUCCESS.getCode(), i18n.getMessage(StatusCode.SUCCESS.getKey()));
            } else {
                return new Response(StatusCode.OPER_FAILED.getCode(), i18n.getMessage(StatusCode.OPER_FAILED.getKey()));
            }

        } else {
            return new Response(UserStatusCode.USER_NOTFOUND.getCode(), i18n.getMessage(UserStatusCode.USER_NOTFOUND.getKey()));
        }
    }

    @Override
    public Map get(String userId) {
        Map map = baseMapper.getUserEditById(userId);
        if (map == null || map.isEmpty()) {
            throw new RsdpSystemException(UserStatusCode.USER_NOTFOUND.getCode(), i18n.getMessage(UserStatusCode.USER_NOTFOUND.getKey()));
        }
        return map;
    }

    @Override
    public List<HashMap> getYxUserList(String czr) {
        return this.baseMapper.getYxUserList(czr);
    }

    @Override
    @Log(module = "用户管理", desc = "初始化密码")
    public Response initPwd(HttpServletRequest request, String czr) {
        TbUser result = this.baseMapper.selectById(StrKits.emptyToStr(request.getParameter("id")));
        if ("0".equals(result.getYxBz()))//已删除
        {
            return new Response(UserStatusCode.USER_DELETED.getCode(), i18n.getMessage(UserStatusCode.USER_DELETED.getKey()));
        } else if ("1".equals(result.getYxBz()))//有效允许初始化
        {
            if ("admin".equals(result.getUserName()))//系统管理员默认为admin
            {
                result.setUserPass(new Md5Hash("admin", null, hashIterations).toString());
            } else {
                result.setUserPass(new Md5Hash(defaultPwd, null, hashIterations).toString());
            }
            result.setXgr(czr);
            result.setXgsj(new Date());
            if (this.baseMapper.updateById(result) > 0) {
                return new Response(StatusCode.SUCCESS.getCode(), i18n.getMessage(StatusCode.SUCCESS.getKey()));
            } else {
                return new Response(StatusCode.OPER_FAILED.getCode(), i18n.getMessage(StatusCode.OPER_FAILED.getKey()));
            }

        } else {
            return new Response(UserStatusCode.USER_NOTFOUND.getCode(), i18n.getMessage(UserStatusCode.USER_NOTFOUND.getKey()));
        }
    }

    @Override
    @Log(module = "登陆用户", desc = "用户信息编辑")
    public Response myEditSave(HttpServletRequest request, String czr) {
        String userid = StrKits.emptyToStr(request.getParameter("hid_id"));
        String xm = StrKits.emptyToStr(request.getParameter("xm"));
        String phone = StrKits.emptyToStr(request.getParameter("phone"));
        String email = StrKits.emptyToStr(request.getParameter("email"));
        String userpass = StrKits.emptyToStr(request.getParameter("userpass"));
        String userpassj = StrKits.emptyToStr(request.getParameter("userpassj"));
        TbUser user = this.baseMapper.selectById(userid);
        if ("0".equals(user.getYxBz())) {
            return new Response(UserStatusCode.USER_DELETED.getCode(), i18n.getMessage(UserStatusCode.USER_DELETED.getKey()));
        } else {
            if (StringUtils.isNotBlank(userpassj)) {
                String oldPass = new Md5Hash(userpassj, null, hashIterations).toString();
                if (oldPass.equals(user.getUserPass())) {
                    user.setUserPass(new Md5Hash(userpass, null, hashIterations).toString());
                } else {
                    return new Response(UserStatusCode.USER_OLDPERR.getCode(), i18n.getMessage(UserStatusCode.USER_OLDPERR.getKey()));
                }
            }
            user.setUserXm(xm);
            user.setUserPhone(phone);
            user.setUserEmail(email);
            user.setXgr(czr);
            user.setXgsj(new Date());
            if (this.baseMapper.updateById(user) > 0) {
                //注销当前用户
                Subject currentUser = SecurityUtils.getSubject();
                currentUser.logout();
                return new Response(UserStatusCode.USER_MODIFY.getCode(), i18n.getMessage(UserStatusCode.USER_MODIFY.getKey()));
            } else {
                return new Response(StatusCode.OPER_FAILED.getCode(), i18n.getMessage(StatusCode.OPER_FAILED.getKey()));
            }
        }
    }
}
